﻿#region Header
// Copyright 2007-2011, Jerónimo Milea
// 
// This file is part of NetJsWire.
// 
//     NetJsWire is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
// 
//     NetJsWire is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
// 
//     You should have received a copy of the GNU General Public License
//     along with NetJsWire.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Windows.Forms.Design.Behavior;
using NetJsWire.Lite.Properties;
using NetJsWire.Lite.Widgets.UI;

namespace NetJsWire.Lite.Designers
{
    public class MarginAndPaddingGlyph : Glyph
    {
        private readonly BehaviorService _behaviorService;
        private readonly IComponentChangeService _changeService;
        private readonly Adorner _marginAndPaddingAdorner;
        private readonly Control _relatedControl;
        private readonly IDesigner _relatedDesigner;
        protected Cursor HitTestCursor = Cursors.Hand;
        protected ISelectionService SelectionService;

        public MarginAndPaddingGlyph(
            BehaviorService behaviorService,
            IComponentChangeService changeService,
            ISelectionService selectionService,
            IDesigner relatedDesigner,
            Adorner marginAndPaddingAdorner )
            : base( new MarginAndPaddingBehavior() )
        {
            _behaviorService = behaviorService;
            _changeService = changeService;
            SelectionService = selectionService;
            _relatedDesigner = relatedDesigner;
            _marginAndPaddingAdorner = marginAndPaddingAdorner;

            _relatedControl = _relatedDesigner.Component as Control;

            _changeService.ComponentChanged += ChangeServiceComponentChanged;
        }

        public override Rectangle Bounds
        {
            get
            {
                var c = _relatedControl;
                var controlRect = _behaviorService.ControlRectInAdornerWindow( _relatedControl );

                var boundsVal = new Rectangle(
                    controlRect.Left - c.Margin.Left,
                    controlRect.Top - c.Margin.Top,
                    controlRect.Width + c.Margin.Right * 2,
                    controlRect.Height + c.Margin.Bottom * 2 );

                return boundsVal;
            }
        }

        // The PaddingBounds property is a Rectangle defined by 
        // the value of the control's Padding property.
        public Rectangle PaddingBounds
        {
            get
            {
                var c = _relatedControl;
                var controlRect = _behaviorService.ControlRectInAdornerWindow( _relatedControl );

                var boundsVal = new Rectangle(
                    controlRect.Left + c.Padding.Left,
                    controlRect.Top + c.Padding.Top,
                    controlRect.Width - c.Padding.Right * 2,
                    controlRect.Height - c.Padding.Bottom * 2 );

                return boundsVal;
            }
        }

        private void ChangeServiceComponentChanged( object sender, ComponentChangedEventArgs e )
        {
            if ( ReferenceEquals( e.Component, _relatedControl ) )
            {
                if ( e.Member.Name == "Title" || e.Member.Name == "Size" )
                {
                    _marginAndPaddingAdorner.Invalidate();
                }
            }
        }

        //protected Rectangle hitBoundsValue = new Rectangle( 10, 5, Bounds.Width - 7, 23 );
        // This is the cursor returned if hit test is positive.

        public override Cursor GetHitTest( Point p )
        {
            if ( new Rectangle( 10, 5, Bounds.Width - 7, 23 ).Contains( p ) )
            {
                return HitTestCursor;
            }

            return null;
        }

        // This method renders the glyph as a Window caption + borders.
        public override void Paint( PaintEventArgs e )
        {
            var backgroundColor = Color.FromArgb( 205, 217, 232 );
            var borderColor = Color.FromArgb( 142, 164, 193 );
            var innerBorderColor = Color.FromArgb( 227, 233, 237 );
            var frameBorderColor = Color.FromArgb( 153, 187, 232 );
            var titleFontColor = Color.FromArgb( 21, 66, 139 );

            using ( var br = new SolidBrush( backgroundColor ) )
            {
                // Caption background
                e.Graphics.FillRectangle( br, Bounds.X + 4, Bounds.Y + 4, Bounds.Width - 8, 23 );

                // Left side
                e.Graphics.FillRectangle( br, Bounds.X + 4, Bounds.Y + 22, 5, Bounds.Height - 31 );

                // Right side
                e.Graphics.FillRectangle( br, Bounds.Width + 3, Bounds.Y + 22, 5, Bounds.Height - 31 );

                // Bottom side
                e.Graphics.FillRectangle( br, Bounds.X + 4, Bounds.Height + 3, Bounds.Width - 8, 5 );
            }

            using ( var pen = new Pen( borderColor ) )
            {
                e.Graphics.DrawRectangle( pen, Bounds.X + 3, Bounds.Y + 3, Bounds.Width - 7, Bounds.Height - 7 );
            }

            using ( var pen = new Pen( innerBorderColor ) )
            {
                e.Graphics.DrawRectangle( pen, Bounds.X + 4, Bounds.Y + 4, Bounds.Width - 9, Bounds.Height - 9 );
            }

            using ( var pen = new Pen( frameBorderColor ) )
            {
                e.Graphics.DrawRectangle( pen, Bounds.X + 9, Bounds.Y + 27, Bounds.Width - 19, Bounds.Height - 37 );
            }

            if ( !string.IsNullOrWhiteSpace( ( ( Window ) _relatedControl ).Title ) )
            {
                using ( var font = new Font( "Tahoma", 11, FontStyle.Bold, GraphicsUnit.Pixel ) )
                {
                    using ( var br = new SolidBrush( titleFontColor ) )
                    {
                        e.Graphics.DrawString( ( ( Window ) _relatedControl ).Title, font, br, Bounds.X + 7, Bounds.Y + 8 );
                    }
                }
            }

            // Tool Buttons drawing
            var index = 0;
            if ( ( ( Window ) _relatedControl ).Closable )
                e.Graphics.DrawImage( Resources.Close, Bounds.Width - ( ( index++ * 16 ) + 11 ), Bounds.Y + 7, 15, 15 );

            if ( ( ( Window ) _relatedControl ).Maximizable )
                e.Graphics.DrawImage( Resources.Maximize, Bounds.Width - ( ( index++ * 16 ) + 11 ), Bounds.Y + 7, 15, 15 );

            if ( ( ( Window ) _relatedControl ).Minimizable )
                e.Graphics.DrawImage( Resources.Minimize, Bounds.Width - ( ( index++ * 16 ) + 11 ), Bounds.Y + 7, 15, 15 );

            if ( ( ( Window ) _relatedControl ).Collapsible )
                e.Graphics.DrawImage( Resources.Collapse, Bounds.Width - ( ( index++ * 16 ) + 11 ), Bounds.Y + 7, 15, 15 );

            var gp = new GraphicsPath();
            gp.AddArc( Bounds.X + 3, Bounds.Y + 3, 5, 5, -90, -90 );
            e.Graphics.DrawPath( new Pen( borderColor ), gp );
        }

        #region Nested type: MarginAndPaddingBehavior

        internal class MarginAndPaddingBehavior : Behavior
        {
            public override bool OnMouseUp( Glyph g, MouseButtons button )
            {
                if ( button == MouseButtons.Left )
                {
                    if ( ( ( MarginAndPaddingGlyph ) g ).SelectionService != null )
                    {
                        ( ( MarginAndPaddingGlyph ) g ).SelectionService.SetSelectedComponents( new[] { ( ( MarginAndPaddingGlyph ) g )._relatedControl } );
                    }
                    //MessageBox.Show( "Sí, ya se, le diste click... :P" );
                    return true;
                }
                return base.OnMouseUp( g, button );
            }

            public override bool OnMouseDoubleClick( Glyph g, MouseButtons button, Point mouseLoc )
            {
                if ( button == MouseButtons.Left )
                {
                    MessageBox.Show( "Sí, ya se, le diste doble click... :P" );

                    return true;
                }

                return base.OnMouseDoubleClick( g, button, mouseLoc );
            }
        }

        #endregion
    }
}